package com.wz.jaav.instruction;

import com.wz.jaav.classreader.classFile.MethodInfo;
import com.wz.jaav.classreader.classFile.attribute.Attribute;
import com.wz.jaav.classreader.classFile.attribute.AttributeInfoCode;
import com.wz.jaav.rtda.Frame;
import com.wz.jaav.rtda.Thread;

public class Interpreter {

    public void interpret(MethodInfo methodInfo){
        AttributeInfoCode codeInfo = getCode(methodInfo);
        Attribute[] attributes = codeInfo.getAttributes();
        int maxLocals = codeInfo.getMaxLocals();
        int maxStack = codeInfo.getMaxStack();
        byte[] codeByte = codeInfo.getCode().getCodeStr();

        Thread thread = new Thread();
        Frame frame = thread.getNewFrame(maxLocals, maxLocals);
        thread.pushFrame(frame);
        loop(thread, codeByte);
    }

    private AttributeInfoCode getCode(MethodInfo methodInfo){
        Attribute[] attributes = methodInfo.getAttributes();
        for (Attribute attribute : attributes) {
            if (attribute.getInfo() instanceof AttributeInfoCode){
                return (AttributeInfoCode) attribute.getInfo();
            }
        }
        return null;
    }

    private void loop(Thread thread, byte[] codeByte){
        Frame frame = thread.popFrame();
        ByteCodeReader reader = new ByteCodeReader();
        for (;;){
            int pc = frame.getNextPc();
            thread.setPc(pc);
            reader.reSet(codeByte, pc);
            byte operCode = reader.readByte();
            int oc = operCode & 0xFF;
            Instuction instuction = Instuctions.getNewInstuction(oc);
            instuction.fetchOperands(reader);
            frame.setNextPc(reader.getPc());
            instuction.execute(frame);
            System.out.println(frame.toString());
        }
    }
}